<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\batch\kuaishou;

use app\enum\CommonEnum;
use app\enum\ConfigEnum;
use app\enum\KuaiShouEnum;
use app\model\KsTargetAgeTaskContentModel;
use app\model\KsTargetAgeTaskLogModel;
use app\model\KsTargetAgeTaskModel;
use app\service\batch\MediaInterface;
use app\service\batch\MediaService;
use app\service\client\AccountService;
use app\service\kuaishou\AdvertiserService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;

class TargetAgePushService extends MediaService implements MediaInterface
{
    /**
     * @var string 批量改定向年龄锁
     */
    protected const BATCH_KEY = ConfigEnum::CACHE_CONFIG[KuaiShouEnum::BATCH_CONFIG_LOCK_KEY]['target_age_push'];

    /**
     * @var null|KsTargetAgeTaskModel 任务模型
     */
    private ?KsTargetAgeTaskModel $taskModel;

    /**
     * @var null|KsTargetAgeTaskContentModel 任务内容模型
     */
    private ?KsTargetAgeTaskContentModel $contentModel;

    /**
     * @var null|KsTargetAgeTaskLogModel 任务日志模型
     */
    private ?KsTargetAgeTaskLogModel $logModel;

    /**
     * 修改出价.
     *
     * @param KsTargetAgeTaskContentModel $model 出价内容模型
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function targetAgePush(KsTargetAgeTaskContentModel $model): bool
    {
        $this->contentModel = $model;
        if (! $this->contentModel->getKey()) {
            return self::setError('未知年龄定向记录失败');
        }

        $this->taskModel = (new KsTargetAgeTaskModel())
            ->where('id', $this->contentModel->getAttr('task_id'))
            ->find();
        if (! $this->taskModel instanceof KsTargetAgeTaskModel || ! $this->taskModel->getKey()) {
            return self::setError('获取年龄定向失败');
        }

        $this->logModel = (new KsTargetAgeTaskLogModel())
            ->where('content_id', $this->contentModel->getKey())
            ->find();
        if (! $this->logModel instanceof KsTargetAgeTaskLogModel || ! $this->logModel->getKey()) {
            return self::setError('获取年龄定向记录失败');
        }

        if (! $this->contentModel->getAttr('ks_project_content')) {
            return self::setError('广告项目结构体为空');
        }
        $project = json_decode($this->contentModel->getAttr('ks_project_content'), true);
        // 修改定向年龄
        $ageArr = self::getTargetAge();
        if ($ageArr === false) {
            return false;
        }
        $project['advertiser_id'] = $this->taskModel->getAttr('advertiser_id');
        $project['ad_dsp_target']['age'] = $ageArr;
        $res = $this->updatetargetAge($project);
        if ($res === false) {
            if (! $this->setTargetAgeFail()) {
                return false;
            }
        } else {
            if (! $this->setTargetAgeSuccess($res)) {
                return false;
            }
        }
        // 更新任务状态
        return $this->targetAgeFinish();
    }

    /**
     *  获取年龄区间.
     * @return array|bool|mixed
     */
    private function getTargetAge()
    {
        if (! $this->contentModel instanceof KsTargetAgeTaskContentModel || ! $this->contentModel->getKey()) {
            return self::setError('获取年龄定向失败');
        }
        if (! $this->contentModel->getAttr('target_age')) {
            return [];
        }
        $content = json_decode($this->contentModel->getAttr('target_age'), true);
        if (! $content) {
            return [];
        }
        if (isset($content['age_type'])) {
            return $content['age_type'];
        }
        return self::setError('定向年龄区间格式错误');
    }

    /**
     *  更新年龄定向.
     *
     * @param array $params 组信息
     * @return bool|mixed|string
     */
    private function updateTargetAge(array $params = [])
    {
        if (! $this->contentModel instanceof KsTargetAgeTaskContentModel || ! $this->contentModel->getKey()) {
            return self::setError('未知组信息');
        }
        $token = AccountService::getToken(CommonEnum::KS_MEDIA, $this->taskModel->getAttr('advertiser_id'));
        if (! $token) {
            return self::setError('token获取失败');
        }
        $headers = [
            'Access-Token' => $token,
            'Content-Type' => 'application/json',
            'K-RealUser-IP' => $this->taskModel->getAttr('ip_address'),
        ];

        unset($params['campaign_id'], $params['put_status'], $params['create_time'], $params['update_time']);
        return AdvertiserService::updateProject($headers, $params);
    }

    /**
     *  出价修改成功.
     *
     * @param mixed $res
     */
    private function setTargetAgeSuccess($res = []): bool
    {
        if (! $this->contentModel instanceof KsTargetAgeTaskContentModel || ! $this->contentModel->getKey()) {
            return self::setError('未知组信息');
        }
        if (! $this->logModel instanceof KsTargetAgeTaskLogModel || ! $this->logModel->getKey()) {
            return self::setError('未知组日志信息');
        }

        $this->contentModel->setAttrs([
            'status' => KsTargetAgeTaskContentModel::STATUS_SUCCESS,
        ]);
        if (! $this->contentModel->save()) {
            return self::setError('保存年龄定向成功结果信息失败');
        }

        $this->logModel->setAttrs([
            'status' => KsTargetAgeTaskLogModel::STATUS_SUCCESS,
            'error_json' => json_encode($res),
        ]);
        if (! $this->logModel->save()) {
            return self::setError('保存年龄定向成功结果日志失败');
        }
        return true;
    }

    /**
     *  出价修改失败.
     */
    private function setTargetAgeFail(): bool
    {
        if (! $this->contentModel instanceof KsTargetAgeTaskContentModel || ! $this->contentModel->getKey()) {
            return self::setError('未知组信息');
        }
        if (! $this->logModel instanceof KsTargetAgeTaskLogModel || ! $this->logModel->getKey()) {
            return self::setError('未知年龄定向日志信息');
        }

        $this->contentModel->setAttrs([
            'status' => KsTargetAgeTaskContentModel::STATUS_FAIL,
        ]);
        if (! $this->contentModel->save()) {
            return self::setError('保存年龄定向错误结果信息失败');
        }

        $this->logModel->setAttrs([
            'status' => KsTargetAgeTaskLogModel::STATUS_FAIL,
            'error_json' => json_encode([AdvertiserService::getError(0)]),
            'error_msg' => AdvertiserService::getError(0),
        ]);
        if (! $this->logModel->save()) {
            return self::setError('保存年龄定向错误结果日志失败');
        }
        return true;
    }

    /**
     * 更新年龄定向状态.
     */
    private function targetAgeFinish(): bool
    {
        if (! $this->taskModel instanceof KsTargetAgeTaskModel || ! $this->taskModel->getKey()) {
            return self::setError('未知年龄定向修改');
        }

        if (! $this->taskModel->getAttr('is_pull')) {
            return true;
        }

        try {
            $waitNum = (new KsTargetAgeTaskContentModel())->where([
                ['task_id', '=', $this->taskModel->getKey()],
                ['status', '=', KsTargetAgeTaskContentModel::STATUS_WAIT],
            ])->count();
            if (! $waitNum) {
                $num = (new KsTargetAgeTaskContentModel())->where('task_id', $this->taskModel->getKey())->count();
                $fallNum = (new KsTargetAgeTaskContentModel())->where([
                    ['task_id', '=', $this->taskModel->getKey()],
                    ['status', '=', KsTargetAgeTaskContentModel::STATUS_FAIL],
                ])->count();

                $this->taskModel->setAttrs([
                    'num' => $num,
                    'status' => $fallNum > 0 ? (KsTargetAgeTaskModel::STATUS_FAIL) : (KsTargetAgeTaskModel::STATUS_SUCCESS),
                ]);

                if (! $this->taskModel->save()) {
                    throw new Exception('设置年龄定向任务状态失败');
                }
            }
            return true;
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }
}
